package utils;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;


/**
 * 查看对象占内存大小
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright:  Copyright (c) 2010</p>
 * <p>Company: DC </p>
 * 
 * @author lijwg
 * @date 2011-8-18
 * @version 1.0
 */
public class MemSizeComputer {
	private static ObjectGenerator objGenerator;

	/**
	 * 
	 * 子类负责覆盖该方法以提供被测试类的实例
	 * 
	 * @return 被测试类的实例
	 */
	protected static Object newInstance() {
		if (objGenerator == null) {
			return null;
		}
		return objGenerator.generate();
	}
	
	/**
	 * 初始化对象生成器
	 * @param generator
	 */
	public static void initGenerator(ObjectGenerator generator){
		MemSizeComputer.objGenerator = generator;
	}

	/**
	 * 
	 * 计算实例的大小（字节数）
	 * 
	 * @return 实例所占内存的字节数
	 * @throws Exception
	 */
	public static int getMemSizeOf() {
		// 垃圾回收
		runGC(4);

		// 提供尽可能多（10万）的实例以使计算结果更精确
		final int count = 100000;
		Object[] objects = new Object[count];

		// 实例化前堆已使用大小
		long heap1 = getUsedMemory();
		// 多实例化一个对象
		for (int i = -1; i < count; ++i) {
			Object object = null;

			// 实例化对象
			object = newInstance();

			if (i >= 0) {
				objects[i] = object;
			} else {
				// 释放第一个对象
				object = null;
				// 垃圾收集
				runGC(4);
				// 实例化之前堆已使用大小
				heap1 = getUsedMemory();
			}
		}

		runGC(4);
		// 实例化之后堆已使用大小
		long heap2 = getUsedMemory();
		final int size = Math.round(((float) (heap2 - heap1)) / count);

		// 释放内存
		for (int i = 0; i < count; ++i) {
			objects[i] = null;
		}
		objects = null;
		return size;
	}
	
	/**
	 * 计算指定对象所占内存大小
	 * @param obj
	 * @return
	 * @throws Exception 
	 */
	public static int getMemSizeOf(Object obj) throws Exception {
		runGC(4);
		long heap1 = getUsedMemory();
		
//			FileOutputStream fos = new FileOutputStream("d:/cache");
//			ObjectOutputStream oos = new ObjectOutputStream(fos);
//			oos.writeObject(obj);
//			oos.flush();
//			oos.close();

		obj = null;
		runGC(4);
		long heap2 = getUsedMemory();
		
		int size = Math.round((float) (heap2 - heap1));
		return size;
	}

	/**
	 * 执行多次以使内存收集更有效
	 * 
	 * @param time
	 */
	public static void runGC(int time) {
		// 
		for (int r = 0; r < time; ++r) {
			_runGC();
		}
	}

	/**
	 * 内存回收
	 */
	public static void _runGC() {
		long usedMem1 = getUsedMemory();
		long usedMem2 = Long.MAX_VALUE;
		for (int i = 0; (usedMem1 < usedMem2) && (i < 500); ++i) {
			Runtime.getRuntime().runFinalization();
			Runtime.getRuntime().gc();
			Thread.currentThread().yield();
			usedMem2 = usedMem1;
			usedMem1 = getUsedMemory();
		}
	}

	/**
	 * 堆中已使用内存
	 * 
	 * @return
	 */
	private static long getUsedMemory() {
		return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
	}

	public static void main(String[] args) throws Exception {
		ObjectGenerator generator2 = new ObjectGenerator(){
			@Override
			Object generate() {
				return new Object();
			}
		};
		MemSizeComputer.initGenerator(generator2);
		System.out.println("所占内存：" + MemSizeComputer.getMemSizeOf() + "字节");
		
		System.out.println("所占内存：" + MemSizeComputer.getMemSizeOf(new ArrayList()) + "字节");
	}

	/**
	 * 对象生成器
	 * <p>Title: </p>
	 * <p>Description: </p>
	 * <p>Copyright:  Copyright (c) 2010</p>
	 * <p>Company: DC </p>
	 * 
	 * @author lijwg
	 * @date 2011-8-18
	 * @version 1.0
	 */
	static abstract class ObjectGenerator{
		abstract Object generate();
	}
}
